openxiangda 1.0.21 → 1.0.24
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 +28 -10
- package/lib/cli.js +723 -11
- package/lib/workspace-init.js +13 -0
- package/openxiangda-skills/SKILL.md +26 -10
- package/openxiangda-skills/references/architecture-patterns.md +44 -22
- package/openxiangda-skills/references/automation-v3.md +2 -0
- package/openxiangda-skills/references/best-practices.md +163 -0
- package/openxiangda-skills/references/connector-resources.md +3 -0
- package/openxiangda-skills/references/notifications.md +80 -0
- package/openxiangda-skills/references/openxiangda-api.md +45 -0
- package/openxiangda-skills/references/pages/page-sdk.md +1 -0
- package/openxiangda-skills/references/pages/workspace-structure.md +5 -3
- package/openxiangda-skills/references/workspace-state.md +6 -0
- package/openxiangda-skills/skills/openxiangda-app/SKILL.md +11 -7
- package/openxiangda-skills/skills/openxiangda-core/SKILL.md +22 -4
- package/openxiangda-skills/skills/openxiangda-form/SKILL.md +6 -1
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +9 -1
- package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +3 -0
- package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +9 -0
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +34 -2
- package/packages/sdk/dist/runtime/index.cjs.map +1 -1
- package/packages/sdk/dist/runtime/index.d.mts +66 -1
- package/packages/sdk/dist/runtime/index.d.ts +66 -1
- package/packages/sdk/dist/runtime/index.mjs +34 -2
- package/packages/sdk/dist/runtime/index.mjs.map +1 -1
- package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +32 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +61 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +44 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/design-style.md +30 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/module-structure.md +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/index.ts +2 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.test.ts +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.ts +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/types.ts +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/index.ts +4 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.test.ts +42 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.ts +23 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.test.ts +63 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.ts +73 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.test.ts +34 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.ts +73 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/types.ts +64 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/schema.ts +57 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/schema.ts +83 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/schema.ts +97 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/page.tsx +1 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/schema.ts +65 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/daily_ticket_digest/index.ts +44 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/sync_roles_to_platform/index.ts +33 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/WorkbenchPage.tsx +36 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/ConfigPanel.tsx +34 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/PreviewPanel.tsx +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/page.config.ts +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/reducer.ts +29 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/styles.css +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/MobilePortalShell.tsx +31 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/modules/MobileHome.tsx +13 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/page.config.ts +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/routes.ts +13 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/styles.css +11 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/PcPortalShell.tsx +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/components/PortalMetric.tsx +11 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/HomeModule.tsx +25 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/TicketsModule.tsx +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/page.config.ts +14 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/routes.ts +19 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/styles.css +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/App.tsx +7 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/TicketOpsPage.tsx +105 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketActionTimeline.tsx +22 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketDetailDrawer.tsx +41 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketTableActions.tsx +55 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/index.tsx +10 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/page.config.ts +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/styles.css +35 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/automation.json +25 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/trigger.json +9 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/notifications/daily-ticket-digest.json +24 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/form-groups/service-ticket-college.json +21 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/roles.json +17 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/workflows/expense-approval-workflow.json +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/ConfirmAction.tsx +22 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/QueryState.tsx +37 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/StatusTag.tsx +20 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/hooks/useTicketOps.ts +96 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/role-governance.ts +48 -0
- package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/service-ticket.ts +113 -0
- package/templates/sy-lowcode-app-workspace/package.json +1 -0
- package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +11 -1
- package/templates/sy-lowcode-app-workspace/tsconfig.examples.json +24 -0
package/lib/workspace-init.js
CHANGED
|
@@ -41,8 +41,14 @@ function initWorkspace(options = {}) {
|
|
|
41
41
|
automations: {},
|
|
42
42
|
menus: {},
|
|
43
43
|
roles: {},
|
|
44
|
+
connectors: {},
|
|
45
|
+
notifications: {
|
|
46
|
+
templates: {},
|
|
47
|
+
typeConfigs: {},
|
|
48
|
+
},
|
|
44
49
|
pagePermissionGroups: {},
|
|
45
50
|
formPermissionGroups: {},
|
|
51
|
+
formSettings: {},
|
|
46
52
|
},
|
|
47
53
|
updatedAt: new Date().toISOString(),
|
|
48
54
|
},
|
|
@@ -69,6 +75,12 @@ function initWorkspace(options = {}) {
|
|
|
69
75
|
};
|
|
70
76
|
}
|
|
71
77
|
|
|
78
|
+
function assertCanInitializeWorkspace(options = {}) {
|
|
79
|
+
const targetDir = path.resolve(options.dir || process.cwd());
|
|
80
|
+
ensureCanInitialize(targetDir, Boolean(options.force));
|
|
81
|
+
return targetDir;
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
function ensureCanInitialize(targetDir, force) {
|
|
73
85
|
if (!fs.existsSync(TEMPLATE_DIR)) {
|
|
74
86
|
throw new Error(`workspace 模板不存在: ${TEMPLATE_DIR}`);
|
|
@@ -135,5 +147,6 @@ function buildNextSteps(targetDir, installedDependencies, bound) {
|
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
module.exports = {
|
|
150
|
+
assertCanInitializeWorkspace,
|
|
138
151
|
initWorkspace,
|
|
139
152
|
};
|
|
@@ -35,27 +35,36 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
35
35
|
```bash
|
|
36
36
|
openxiangda login https://dev-lowcode.example.com --profile dev
|
|
37
37
|
```
|
|
38
|
-
4. Check current context before any write:
|
|
38
|
+
4. Check the CLI version and current context before any write:
|
|
39
39
|
```bash
|
|
40
|
+
openxiangda update check --json
|
|
40
41
|
openxiangda env --profile dev
|
|
41
42
|
openxiangda auth status --profile dev
|
|
42
43
|
```
|
|
43
|
-
|
|
44
|
+
If `updateAvailable` is true, update from the official npm registry before continuing:
|
|
44
45
|
```bash
|
|
45
|
-
openxiangda
|
|
46
|
+
openxiangda update install
|
|
47
|
+
```
|
|
48
|
+
5. Ensure there is a local app workspace. Local workspace state is authoritative:
|
|
49
|
+
- If the current workspace already has `.openxiangda/state.json` with an app binding for the target profile, use that app.
|
|
50
|
+
- If the user explicitly provides an `appType` or asks to reuse an existing app, bind to that exact app.
|
|
51
|
+
- If the current folder is empty or has no local app binding, create a new app and workspace; do not search the platform for similar app names.
|
|
52
|
+
```bash
|
|
53
|
+
openxiangda workspace init ./my-app-workspace --profile dev --app-name "示例应用"
|
|
46
54
|
cd ./my-app-workspace
|
|
47
55
|
pnpm install
|
|
48
56
|
```
|
|
49
|
-
6.
|
|
57
|
+
6. To bind an existing app only when explicitly requested:
|
|
50
58
|
```bash
|
|
51
|
-
openxiangda app
|
|
52
|
-
# or
|
|
53
|
-
openxiangda app create "示例应用" --profile dev
|
|
59
|
+
openxiangda workspace init ./my-app-workspace --profile dev --app-type APP_XXXX
|
|
60
|
+
# or, inside an existing workspace:
|
|
54
61
|
openxiangda workspace bind --profile dev --app-type APP_XXXX
|
|
55
|
-
|
|
62
|
+
```
|
|
63
|
+
7. Publish from the local workspace:
|
|
64
|
+
```bash
|
|
56
65
|
openxiangda workspace publish --profile dev
|
|
57
66
|
```
|
|
58
|
-
|
|
67
|
+
8. For multi-platform publishing, always pass `--profile` explicitly:
|
|
59
68
|
```bash
|
|
60
69
|
openxiangda workspace publish --profile prod
|
|
61
70
|
```
|
|
@@ -63,7 +72,10 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
63
72
|
## Rules
|
|
64
73
|
|
|
65
74
|
- Never ask the user for `appKey`, `appSecret`, `AK`, or `SK`.
|
|
66
|
-
- If `openxiangda` is not available in PATH, the CLI package is not installed or linked. In this repo, use `npm link`; in a packaged install, use `npm install -g
|
|
75
|
+
- If `openxiangda` is not available in PATH, the CLI package is not installed or linked. In this repo, use `npm link`; in a packaged install, use `npm install -g openxiangda@latest --registry=https://registry.npmjs.org`.
|
|
76
|
+
- Always prefer the official npm registry for OpenXiangda updates. Domestic mirrors may lag and return an older package.
|
|
77
|
+
- Run `openxiangda update check --json` when starting substantial work or diagnosing version/skill mismatches. If it reports an update, run `openxiangda update install` so the CLI and installed skills match. If the installed CLI does not support `update`, run `npm install -g openxiangda@latest --registry=https://registry.npmjs.org` and then `openxiangda skill install --force`.
|
|
78
|
+
- Local `.openxiangda/state.json` is the source of truth for app binding. In an empty folder or unbound workspace, create a new app with `workspace init --app-name`; do not infer reuse from similar platform app names.
|
|
67
79
|
- If there is no `sy-lowcode-app-workspace`, create one with `openxiangda workspace init <dir>` before writing forms, pages, or JS_CODE nodes.
|
|
68
80
|
- Never treat `openxiangda form create` as page generation. It only creates a low-level platform form shell for diagnostics or for workspace publish internals. The source of user-facing pages is `sy-lowcode-app-workspace`.
|
|
69
81
|
- Publish normal form pages, workflow form pages, and custom code pages through `openxiangda workspace publish --profile <name>` from the app workspace.
|
|
@@ -71,6 +83,7 @@ When the user provides a root domain such as `https://yida.wisejob.cn/`, use it
|
|
|
71
83
|
- Use logical resource codes in local files. Platform-specific IDs such as `formUuid`, `pageId`, `workflowId`, and `automationId` must be isolated by profile.
|
|
72
84
|
- Put engineering-managed resources in `src/resources/` and use `openxiangda resource validate|plan|publish|pull`. `workspace publish` publishes workspace forms/pages first, then runs non-destructive resource upsert. Only pass `--prune` when the user explicitly wants local manifests to delete platform-side extras.
|
|
73
85
|
- For external APIs, create a connector manifest in `src/resources/connectors/` and call it from pages through `sdk.connector`; never put third-party API keys in page source.
|
|
86
|
+
- Before scaffolding a real app, complex page, data management page, portal shell, status lifecycle, role governance, or automation, read `references/best-practices.md` and pick the architecture first. Prefer copying the relevant pattern from `examples/best-practices/` into `src/` instead of generating a single large page file.
|
|
74
87
|
- Before publishing to another platform, verify the workspace is bound for that profile. Resource IDs from one profile must not be reused for another profile.
|
|
75
88
|
- Use `openxiangda app snapshot <APP_XXX> --profile <name> --json` for diagnosis before changing an existing app.
|
|
76
89
|
- Run write commands that update `.openxiangda/state.json` sequentially within the same workspace. Read-only commands can run in parallel.
|
|
@@ -105,6 +118,8 @@ Core CLI / state:
|
|
|
105
118
|
- `references/openxiangda-api.md` — `/openxiangda-api/v1` request and response fields.
|
|
106
119
|
- `references/workspace-state.md` — `.openxiangda/state.json` shape and profile isolation rules.
|
|
107
120
|
- `references/connector-resources.md` — `src/resources` manifests, connector schema, and SDK connector calls.
|
|
121
|
+
- `references/notifications.md` — `src/resources/notifications`, notification templates/type bindings, and `sdk.notification` / `ctx.notification`.
|
|
122
|
+
- `references/best-practices.md` — initialized examples for modular pages, state lifecycles, role governance, permission isolation, high-performance queries, portal shells, workflow boundaries, and automation patterns.
|
|
108
123
|
|
|
109
124
|
Form authoring:
|
|
110
125
|
|
|
@@ -129,5 +144,6 @@ Platform domain knowledge (read these first when generating forms or pages so th
|
|
|
129
144
|
- `references/platform-data-model.md` — how the platform persists field values (JSONB, `{label, value}` for option fields, attachment shape, etc.). Use this whenever you write, render, or diagnose form data.
|
|
130
145
|
- `references/style-system.md` — three-layer style architecture, CSS namespace, and the no-hardcoded-color rule. Use this before writing any page or form CSS.
|
|
131
146
|
- `references/architecture-patterns.md` — CRUD data flow, `DataManagementList` pattern, recommended directory layout for `src/pages` and `src/forms`. Use this before scaffolding a new page or list view.
|
|
147
|
+
- `references/best-practices.md` — read this before implementing app-level business patterns; it points to `examples/best-practices/` and explains when to use status fields instead of workflow.
|
|
132
148
|
- `references/component-guide.md` — when to pick platform components vs. raw Ant Design vs. custom components, with the rules for option fields. Use this before introducing a new component.
|
|
133
149
|
- `references/troubleshooting.md` — known failure modes (missing styles, `options` runtime errors, broken option rendering, etc.) and how to fix them. Use this when something does not behave as expected.
|
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
| 编写 REST API | 平台自动生成数据 API |
|
|
30
30
|
| 维护权限中间件 | 表单字段级权限 + 部门/角色 |
|
|
31
31
|
| 自建文件存储 | `AttachmentField` 直接接入平台存储 |
|
|
32
|
-
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
| 业务状态流转 | 表单 + `status` 字段 + 操作日志 + domain/service |
|
|
33
|
+
| 真审批流程 | 表单 + workflow + js-code-nodes |
|
|
34
|
+
|
|
35
|
+
AI Agent 在该平台上写代码时,**不应该考虑数据库、表结构、后端接口**——这些由表单 schema 自动派生。
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
@@ -144,12 +145,20 @@ export default function InstrumentListPage() {
|
|
|
144
145
|
| 页面类型 | 实现方式 | 适用场景 |
|
|
145
146
|
| --- | --- | --- |
|
|
146
147
|
| 表单录入 / 编辑页 | `src/forms/xxx/` (`schema.ts` + `page.tsx`) | 新增数据、修改数据 |
|
|
147
|
-
| 数据管理页 | `src/pages/xxx/` 使用 `DataManagementList` | 列表、查询、批量操作、导出 |
|
|
148
|
-
|
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
| 数据管理页 | `src/pages/xxx/` 使用 `DataManagementList` | 列表、查询、批量操作、导出 |
|
|
149
|
+
| 状态流转页 | 普通表单 + 状态字段 + 操作日志 + 代码页 service | 工单、订单、任务等业务状态变化 |
|
|
150
|
+
| 流程表单页 | `src/forms/xxx/` 关联 workflow | 真实审批流程发起、节点处理、审批意见 |
|
|
151
|
+
| 自定义业务页 | `src/pages/xxx/` 自由编码 | 仪表盘、看板、复杂交互、对外门户 |
|
|
152
|
+
| 详情页 | `src/pages/xxx/[id].tsx` 使用 `FormSummaryCard` 等 | 查看单条数据、关联记录 |
|
|
153
|
+
|
|
154
|
+
> AI Agent 在创建新页面前,先按上表判断「应该走表单还是代码页」,避免把列表场景误塞进表单页。
|
|
155
|
+
|
|
156
|
+
### 4.1 状态流转不是审批流
|
|
157
|
+
|
|
158
|
+
- 普通业务流转默认使用普通表单:`status` 字段、责任人/归属冗余字段、操作日志表、domain 状态机、service 统一提交。
|
|
159
|
+
- 每次状态变更都由 service 完成,统一写操作日志并更新责任人、归属、更新时间等冗余字段。
|
|
160
|
+
- workflow 只用于真实审批:审批人、审批任务、同意/驳回、审批意见、节点权限、流程记录明确存在的场景。
|
|
161
|
+
- 不要把「待处理 / 处理中 / 已完成 / 已关闭」这类状态流转建成流程表单。
|
|
153
162
|
|
|
154
163
|
---
|
|
155
164
|
|
|
@@ -175,7 +184,7 @@ export default function InstrumentListPage() {
|
|
|
175
184
|
- **UI 库分端**:
|
|
176
185
|
- PC → `antd`
|
|
177
186
|
- Mobile → `antd-mobile`
|
|
178
|
-
- **逻辑层共享**:`src/domain/` 与 `src/shared/services/` 在两端复用,确保业务规则一处实现。
|
|
187
|
+
- **逻辑层共享**:`src/domain/` 与 `src/shared/services/` 在两端复用,确保业务规则一处实现。
|
|
179
188
|
|
|
180
189
|
### 5.2 共享 / 分离原则
|
|
181
190
|
|
|
@@ -228,15 +237,28 @@ forms ──▶ shared ──▶ domain
|
|
|
228
237
|
```
|
|
229
238
|
|
|
230
239
|
- `domain/` 不依赖 `shared/` 或 UI。
|
|
231
|
-
- `shared/` 不依赖 `pages/` 或 `forms/`。
|
|
232
|
-
- 反向依赖(如 domain 导入 pages)= 立刻拒绝。
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
##
|
|
237
|
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
-
|
|
240
|
+
- `shared/` 不依赖 `pages/` 或 `forms/`。
|
|
241
|
+
- 反向依赖(如 domain 导入 pages)= 立刻拒绝。
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 7. 查询与交互性能
|
|
246
|
+
|
|
247
|
+
- 列表必须走分页接口,传 `currentPage`、`pageSize`、排序和结构化条件。
|
|
248
|
+
- 禁止一次取大 `pageSize` 再在页面内筛选。
|
|
249
|
+
- 默认不要使用 `searchKeyWord`;多字段模糊查询用 `filterGroup` + `OR`,并显式指定字段。
|
|
250
|
+
- 查询条件构造放在 `domain/` 或 `shared/services/`,不要散落在 TSX 事件处理里。
|
|
251
|
+
- 列表刷新时保留当前数据,使用局部刷新态,避免整页闪烁。
|
|
252
|
+
- 操作需要统一的确认、pending、成功反馈、失败刷新或回滚。
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 速查 Checklist(AI Agent 自检)
|
|
257
|
+
|
|
258
|
+
- [ ] 新增数据场景:是否已经定义表单 schema?
|
|
259
|
+
- [ ] 列表/查询场景:是否使用 `DataManagementList` 而非平台 view?
|
|
260
|
+
- [ ] 查询:是否使用分页和结构化条件,而不是大 pageSize、页面内过滤或 `searchKeyWord`?
|
|
261
|
+
- [ ] 流程判断:是否确认这是「真审批」,而不是普通状态流转?
|
|
262
|
+
- [ ] 菜单绑定:是否指向代码页 `--type=page`?
|
|
263
|
+
- [ ] PC/Mobile:是否分离页面、共享 domain?
|
|
264
|
+
- [ ] 目录:业务逻辑是否落在 `domain/`,未污染 UI 层?
|
|
@@ -123,6 +123,8 @@ The backend runs the snapshot in the trusted Node runtime, applies the node time
|
|
|
123
123
|
|
|
124
124
|
Runtime context includes `ctx.triggerEvent`, `ctx.formData`, `ctx.workflowData`, `ctx.operator`, `ctx.app`, `ctx.variables`, and `ctx.node`. Data/process bridge methods include `ctx.methods.queryOneData`, `queryManyData`, `updateOneData`, `updateDataByFormInstanceId`, `updateManyData`, `createOneData`, `terminateProcess`, and `getAllParentDepartments`.
|
|
125
125
|
|
|
126
|
+
Notification bridge methods include `ctx.notification.sendByType`, `batchSendByType`, `findConfig`, and `previewTemplate`. For custom business messages, create `src/resources/notifications/` first and use its `notificationType`; do not call legacy `/api/notification-config/*` endpoints directly.
|
|
127
|
+
|
|
126
128
|
Example `src/js-code-nodes/scheduled_reconcile/index.ts`:
|
|
127
129
|
|
|
128
130
|
```ts
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# OpenXiangda Best Practices
|
|
2
|
+
|
|
3
|
+
Use this reference before scaffolding a real app, a complex page, a data
|
|
4
|
+
management view, a portal shell, role governance, notification automation, or a
|
|
5
|
+
business lifecycle flow.
|
|
6
|
+
|
|
7
|
+
The workspace template includes examples under:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
examples/best-practices/
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
These examples are copied by `openxiangda workspace init`, but they are not
|
|
14
|
+
published by default. Copy only the selected pattern into `src/`, then adapt the
|
|
15
|
+
form codes, field names, permissions, and page route names.
|
|
16
|
+
|
|
17
|
+
## AI Development Flow
|
|
18
|
+
|
|
19
|
+
1. Choose the architecture before writing code:
|
|
20
|
+
- normal form
|
|
21
|
+
- custom form page
|
|
22
|
+
- data management page
|
|
23
|
+
- custom data management page
|
|
24
|
+
- app-shell PC portal
|
|
25
|
+
- app-shell mobile portal
|
|
26
|
+
- pure interactive workbench
|
|
27
|
+
- business status lifecycle
|
|
28
|
+
- real approval workflow
|
|
29
|
+
- automation / JS_CODE
|
|
30
|
+
- role governance / permissions
|
|
31
|
+
2. Read the matching files in `examples/best-practices/`.
|
|
32
|
+
3. Copy the smallest useful slice into `src/`.
|
|
33
|
+
4. Keep view code thin; put reusable business logic in `domain/` and platform
|
|
34
|
+
calls in `shared/services/`.
|
|
35
|
+
5. Run `pnpm examples:check` while changing examples, and `pnpm check` after
|
|
36
|
+
copying code into the app source.
|
|
37
|
+
|
|
38
|
+
## State Flow Is Not Workflow
|
|
39
|
+
|
|
40
|
+
Most business processes are status lifecycles, not approval workflows.
|
|
41
|
+
|
|
42
|
+
Use a normal form plus:
|
|
43
|
+
|
|
44
|
+
- a `status` field
|
|
45
|
+
- responsibility fields such as `ownerUserId`, `ownerDeptId`, `collegeId`,
|
|
46
|
+
`classId`
|
|
47
|
+
- an action log form
|
|
48
|
+
- a pure state machine in `domain/<feature>/state-machine.ts`
|
|
49
|
+
- a service method that changes status and writes the log in one path
|
|
50
|
+
- optional automation / JS_CODE for timed reminders or backend follow-up
|
|
51
|
+
|
|
52
|
+
Use workflow only when there are real approval tasks:
|
|
53
|
+
|
|
54
|
+
- approver assignment
|
|
55
|
+
- agree / reject / transfer / countersign behavior
|
|
56
|
+
- approval opinions
|
|
57
|
+
- node-level permissions
|
|
58
|
+
- process task records and audit requirements
|
|
59
|
+
- notification or JS_CODE nodes tied to approval nodes
|
|
60
|
+
|
|
61
|
+
Do not model ordinary "pending -> processing -> resolved -> closed" state
|
|
62
|
+
changes as workflow forms.
|
|
63
|
+
|
|
64
|
+
## Layering Rules
|
|
65
|
+
|
|
66
|
+
Use this dependency direction:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
pages/forms -> shared -> domain
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `domain/<feature>/`: pure TypeScript business types, state machine,
|
|
73
|
+
permission predicates, and query condition builders. No React, Ant Design,
|
|
74
|
+
runtime SDK, CSS, or platform IDs.
|
|
75
|
+
- `shared/services/<feature>.ts`: SDK/API access, paginated queries, status
|
|
76
|
+
updates, log writes, resource calls.
|
|
77
|
+
- `shared/hooks/<feature>/`: loading, refresh, submit pending, error handling,
|
|
78
|
+
optimistic or rollback behavior.
|
|
79
|
+
- `shared/components/`: reusable empty, loading, error, status tag,
|
|
80
|
+
confirmation, timeline, and list action components.
|
|
81
|
+
- `pages/<feature>/components/`: page-local reusable components.
|
|
82
|
+
- `pages/<feature>/styles.css`: page CSS namespace. Do not put all styling in
|
|
83
|
+
TSX.
|
|
84
|
+
- `pages/<feature>/index.tsx`: entry and composition only. Avoid large business
|
|
85
|
+
logic blocks here.
|
|
86
|
+
|
|
87
|
+
PC and mobile pages may have different layout/components, but must reuse the
|
|
88
|
+
same `domain/` and `shared/services/` when the business behavior is the same.
|
|
89
|
+
|
|
90
|
+
## Module Size Rules
|
|
91
|
+
|
|
92
|
+
- Avoid single-file pages. A page file over about 250 lines should be split.
|
|
93
|
+
- Move table columns, filter definitions, route configs, status configs, and
|
|
94
|
+
action visibility rules into separate files.
|
|
95
|
+
- Do not let page components assemble complex API payloads directly. Call a hook
|
|
96
|
+
or service.
|
|
97
|
+
- Keep shared modules independent from specific page folders.
|
|
98
|
+
- Keep domain functions unit-testable without a browser or platform runtime.
|
|
99
|
+
|
|
100
|
+
## Permission And Data Isolation
|
|
101
|
+
|
|
102
|
+
For apps with dynamic roles:
|
|
103
|
+
|
|
104
|
+
1. Create an app role maintenance form, such as `app-role`.
|
|
105
|
+
2. Use automation / JS_CODE to sync role records to platform roles.
|
|
106
|
+
3. Add redundant ownership fields to business forms, for example:
|
|
107
|
+
- `collegeId`
|
|
108
|
+
- `classId`
|
|
109
|
+
- `ownerDeptId`
|
|
110
|
+
- `ownerUserId`
|
|
111
|
+
- `roleCode`
|
|
112
|
+
4. Create page permission groups for entry visibility.
|
|
113
|
+
5. Create form permission groups with condition-based data permissions for real
|
|
114
|
+
data isolation.
|
|
115
|
+
|
|
116
|
+
Frontend button hiding is only user experience. It is not permission control.
|
|
117
|
+
Every sensitive action must still be protected by platform role/form permission
|
|
118
|
+
groups or backend-side JS_CODE checks.
|
|
119
|
+
|
|
120
|
+
## Query Performance
|
|
121
|
+
|
|
122
|
+
- Always use paginated APIs with `currentPage`, `pageSize`, sort, and structured
|
|
123
|
+
conditions.
|
|
124
|
+
- Do not fetch a huge page and filter in the browser.
|
|
125
|
+
- Do not default to `searchKeyWord`. It is broad and expensive.
|
|
126
|
+
- For multi-field fuzzy search, build `filterGroup` with `OR` across explicit
|
|
127
|
+
fields.
|
|
128
|
+
- Put query construction in `domain/<feature>/ticket-query.ts` or the service
|
|
129
|
+
layer, not inside JSX.
|
|
130
|
+
- Keep current table/list data visible during refresh and show local refresh
|
|
131
|
+
state to avoid flicker.
|
|
132
|
+
|
|
133
|
+
## Interaction Rules
|
|
134
|
+
|
|
135
|
+
- Every list/detail page needs loading, empty, error, refresh, and submit-pending
|
|
136
|
+
states.
|
|
137
|
+
- Destructive or state-changing actions need confirmation.
|
|
138
|
+
- Show processing feedback and success/failure feedback.
|
|
139
|
+
- On failure, refresh or rollback the affected row instead of leaving stale UI.
|
|
140
|
+
- Keep interaction styles consistent across PC and mobile, but do not force the
|
|
141
|
+
same layout component onto both viewports.
|
|
142
|
+
|
|
143
|
+
## Template Catalog
|
|
144
|
+
|
|
145
|
+
- `customer-profile`: standard form schema with validation, members,
|
|
146
|
+
departments, attachments, and child table.
|
|
147
|
+
- `service-ticket-lifecycle`: status lifecycle with ticket form, action-log
|
|
148
|
+
form, state machine, service layer, and operation log.
|
|
149
|
+
- `service-ticket-ops`: custom data management page based on
|
|
150
|
+
`DataManagementList`, split into page, components, hook, query builder, and
|
|
151
|
+
detail drawer.
|
|
152
|
+
- `role-governance`: role maintenance form, role sync JS_CODE, redundant
|
|
153
|
+
ownership fields, and permission-group resource examples.
|
|
154
|
+
- `pc-portal-shell`: app-shell PC portal with routes, modules, components, and
|
|
155
|
+
services.
|
|
156
|
+
- `mobile-portal-shell`: app-shell mobile portal with mobile-only components
|
|
157
|
+
reusing the same domain/service layer.
|
|
158
|
+
- `interactive-workbench`: pure interactive page with reducer, modular panels,
|
|
159
|
+
preview, loading/error, and batch operations.
|
|
160
|
+
- `expense-approval-workflow`: real approval workflow example; use only for
|
|
161
|
+
approval scenarios.
|
|
162
|
+
- `daily-ticket-digest`: automation / JS_CODE example for paginated overdue
|
|
163
|
+
query, notification, and log writing.
|
|
@@ -5,6 +5,7 @@ OpenXiangda engineering resources live under `src/resources/`.
|
|
|
5
5
|
Common folders:
|
|
6
6
|
|
|
7
7
|
- `connectors`
|
|
8
|
+
- `notifications`
|
|
8
9
|
- `roles`
|
|
9
10
|
- `menus`
|
|
10
11
|
- `workflows`
|
|
@@ -24,6 +25,8 @@ openxiangda resource pull --profile dev
|
|
|
24
25
|
|
|
25
26
|
Connector manifests use stable `code` values. The platform maps connector `code` to the existing connector `methodName`, and API `code` to the existing connector API `methodName`.
|
|
26
27
|
|
|
28
|
+
Notification manifests live under `src/resources/notifications/` and contain `templates` plus `typeConfigs`. See `notifications.md` before generating reminders or message templates.
|
|
29
|
+
|
|
27
30
|
```json
|
|
28
31
|
{
|
|
29
32
|
"code": "crm",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Notification Resources
|
|
2
|
+
|
|
3
|
+
Use notification resources when a page, workflow, or automation needs reusable message templates.
|
|
4
|
+
|
|
5
|
+
AI generation rule: declare notification resources first, then call `sdk.notification` in code pages or `ctx.notification` in JS_CODE. Do not hardcode `/api/notification-config/*` or store channel credentials in source.
|
|
6
|
+
|
|
7
|
+
## Resource Files
|
|
8
|
+
|
|
9
|
+
Place JSON under `src/resources/notifications/`.
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"templates": [
|
|
14
|
+
{
|
|
15
|
+
"code": "reservation_reminder",
|
|
16
|
+
"name": "预约提醒",
|
|
17
|
+
"content": "{{title}}",
|
|
18
|
+
"variables": ["title", "instrumentName", "startTime"],
|
|
19
|
+
"channelsConfig": {
|
|
20
|
+
"inapp": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"content": "{{instrumentName}} 将于 {{startTime}} 开始"
|
|
23
|
+
},
|
|
24
|
+
"dingding": {
|
|
25
|
+
"enabled": true,
|
|
26
|
+
"content": "{{title}}"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"typeConfigs": [
|
|
32
|
+
{
|
|
33
|
+
"notificationType": "reservation_reminder",
|
|
34
|
+
"templateCode": "reservation_reminder",
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"priority": 0
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For form-level notifications, add `level: "form"` and `formCode` to both the template and type config. Prefer `formCode`; the CLI resolves `formUuid` per profile.
|
|
43
|
+
|
|
44
|
+
Allowed channels: `inapp`, `email`, `dingding`, `wechat`, `thirdparty_todo`.
|
|
45
|
+
|
|
46
|
+
Do not include `token`, `secret`, `password`, `authorization`, `auth`, `credential`, or `headers` fields. Platform admins configure channel credentials outside resources.
|
|
47
|
+
|
|
48
|
+
## Runtime Calls
|
|
49
|
+
|
|
50
|
+
Code pages:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
await sdk.notification.sendByType({
|
|
54
|
+
notificationType: "reservation_reminder",
|
|
55
|
+
recipientId: userId,
|
|
56
|
+
payload: {
|
|
57
|
+
title: "预约提醒",
|
|
58
|
+
instrumentName,
|
|
59
|
+
startTime,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Automation or workflow JS_CODE:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
export default async function notify(ctx) {
|
|
68
|
+
await ctx.notification.sendByType({
|
|
69
|
+
notificationType: "reservation_reminder",
|
|
70
|
+
recipientId: ctx.operator.userId,
|
|
71
|
+
payload: {
|
|
72
|
+
title: "预约提醒",
|
|
73
|
+
instrumentName: ctx.formData.current.instrument_name,
|
|
74
|
+
startTime: ctx.formData.current.start_time,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Use `work_notification` for simple declarative notifications. Use JS_CODE only for dynamic recipients, conditional sending, or payload assembly.
|
|
@@ -205,6 +205,51 @@ Requires Bearer token. Deletes a menu item.
|
|
|
205
205
|
|
|
206
206
|
Requires Bearer token. Updates menu sorting and parent relationships in batch.
|
|
207
207
|
|
|
208
|
+
## Notifications
|
|
209
|
+
|
|
210
|
+
### POST `/apps/:appType/notifications/send-by-type`
|
|
211
|
+
|
|
212
|
+
Requires Bearer token. Sends a notification in the current app scope.
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"notificationType": "reservation_reminder",
|
|
217
|
+
"recipientId": "user-id",
|
|
218
|
+
"payload": {
|
|
219
|
+
"title": "预约提醒"
|
|
220
|
+
},
|
|
221
|
+
"channels": ["inapp"]
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### POST `/apps/:appType/notifications/batch-send-by-type`
|
|
226
|
+
|
|
227
|
+
Requires Bearer token. Sends one notification type to multiple recipients.
|
|
228
|
+
|
|
229
|
+
### GET `/apps/:appType/notifications/templates`
|
|
230
|
+
|
|
231
|
+
Requires Bearer token. Lists app/form notification templates.
|
|
232
|
+
|
|
233
|
+
### PUT `/apps/:appType/notifications/templates/:code`
|
|
234
|
+
|
|
235
|
+
Requires app admin permission. Upserts an app/form notification template by code.
|
|
236
|
+
|
|
237
|
+
### POST `/apps/:appType/notifications/templates/preview`
|
|
238
|
+
|
|
239
|
+
Requires Bearer token. Body uses `templateCode` or `templateId` plus `payload`.
|
|
240
|
+
|
|
241
|
+
### GET `/apps/:appType/notifications/type-configs`
|
|
242
|
+
|
|
243
|
+
Requires Bearer token. Lists notification type bindings.
|
|
244
|
+
|
|
245
|
+
### GET `/apps/:appType/notifications/type-configs/:notificationType`
|
|
246
|
+
|
|
247
|
+
Requires Bearer token. Resolves the active binding by notification type and optional `formUuid`.
|
|
248
|
+
|
|
249
|
+
### PUT `/apps/:appType/notifications/type-configs/:notificationType`
|
|
250
|
+
|
|
251
|
+
Requires app admin permission. Upserts a binding with `templateCode` or `templateId`.
|
|
252
|
+
|
|
208
253
|
### GET `/apps/:appType/workflows`
|
|
209
254
|
|
|
210
255
|
Requires Bearer token. Lists workflow definitions in the app. Supports `formUuid`, `isPublished`, `page`, and `pageSize` query parameters.
|
|
@@ -7,6 +7,7 @@ Guidelines:
|
|
|
7
7
|
- Do not hardcode `/openxiangda-api` calls inside end-user page components unless the page is explicitly an admin tool.
|
|
8
8
|
- Prefer SDK modules for form data, user context, permissions, and platform navigation.
|
|
9
9
|
- Use `sdk.connector.invoke`, `sdk.connector.call("connector.api")`, or `sdk.connector.download` for external services. The SDK calls the platform runtime connector endpoint; it must not call third-party domains directly.
|
|
10
|
+
- Use `sdk.notification.sendByType` and `batchSendByType` for reusable business messages. Custom notification types must be declared in `src/resources/notifications/` and published with `openxiangda resource publish`.
|
|
10
11
|
- For the current user's department hierarchy, use `sdk.department.getCurrentUserParentDepartments()`; do not hardcode `GET /department/:id/parentDepartments` in page code.
|
|
11
12
|
- Keep API calls behind small local functions so generated UI stays testable.
|
|
12
13
|
- Treat user context and tenant context as runtime-provided values.
|
|
@@ -5,16 +5,18 @@ Form pages, workflow form pages, and custom code pages live in `sy-lowcode-app-w
|
|
|
5
5
|
Create a new workspace with:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
openxiangda workspace init ./my-app-workspace
|
|
8
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
9
9
|
cd ./my-app-workspace
|
|
10
10
|
pnpm install
|
|
11
|
-
openxiangda workspace bind --profile <name> --app-type APP_XXXX
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Local workspace state is authoritative. If the current folder has no app binding, create a new app; do not search the platform for similar app names.
|
|
14
|
+
|
|
15
|
+
Bind an existing app only when the user explicitly provides `appType` or asks to reuse that app:
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
18
|
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXXX
|
|
19
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXXX
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
Typical code page layout:
|
|
@@ -31,6 +31,10 @@ Tokens never belong in the project. User tokens live in `~/.openxiangda/profiles
|
|
|
31
31
|
"menus": {},
|
|
32
32
|
"roles": {},
|
|
33
33
|
"connectors": {},
|
|
34
|
+
"notifications": {
|
|
35
|
+
"templates": {},
|
|
36
|
+
"typeConfigs": {}
|
|
37
|
+
},
|
|
34
38
|
"pagePermissionGroups": {},
|
|
35
39
|
"formPermissionGroups": {},
|
|
36
40
|
"formSettings": {}
|
|
@@ -44,6 +48,8 @@ Tokens never belong in the project. User tokens live in `~/.openxiangda/profiles
|
|
|
44
48
|
|
|
45
49
|
- Profile is the deployment boundary.
|
|
46
50
|
- `baseUrl` is the backend API base. On standard private deployments it is `<origin>/service`; management pages use `/platform`, and app runtime pages use `/view`.
|
|
51
|
+
- Local state is authoritative for app binding. If a workspace has no `appType` for the target profile, create a new app/workspace with `openxiangda workspace init <dir> --profile <name> --app-name "应用名称"`.
|
|
52
|
+
- Do not search platform apps or reuse similar names unless the user explicitly asks to reuse an existing app or provides an `appType`.
|
|
47
53
|
- Local resource keys are logical codes.
|
|
48
54
|
- Live IDs and lightweight runtime aliases are nested under the profile that produced them.
|
|
49
55
|
- Do not store business configuration or secrets in `.openxiangda/state.json`; store those in `src/resources/`.
|
|
@@ -19,16 +19,16 @@ openxiangda auth status --profile <name>
|
|
|
19
19
|
If the workspace is not bound:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
openxiangda app
|
|
23
|
-
|
|
22
|
+
openxiangda workspace init ./my-app-workspace --profile <name> --app-name "应用名称"
|
|
23
|
+
cd ./my-app-workspace
|
|
24
|
+
pnpm install
|
|
24
25
|
```
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
Bind to an existing app only when the user explicitly provides `appType` or asks to reuse an existing platform app:
|
|
27
28
|
|
|
28
29
|
```bash
|
|
29
30
|
openxiangda workspace init ./my-app-workspace --profile <name> --app-type APP_XXX
|
|
30
|
-
|
|
31
|
-
pnpm install
|
|
31
|
+
openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
For menu work:
|
|
@@ -39,7 +39,7 @@ openxiangda menu create main --name "主菜单" --type nav --profile <name>
|
|
|
39
39
|
openxiangda menu create customer-entry --name "客户信息" --type receipt --form-code customer --profile <name>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
If the app
|
|
42
|
+
If the user explicitly asks to create an app without initializing a workspace:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
45
|
openxiangda app create "应用名称" --profile <name>
|
|
@@ -50,9 +50,11 @@ openxiangda workspace bind --profile <name> --app-type APP_XXX
|
|
|
50
50
|
|
|
51
51
|
- Never ask for AK/SK.
|
|
52
52
|
- Always pass `--profile` for publish or cross-platform operations.
|
|
53
|
-
-
|
|
53
|
+
- Local `.openxiangda/state.json` is authoritative. If the user starts from a new empty directory or the workspace has no app binding, create a new app with `openxiangda workspace init <dir> --profile <name> --app-name "应用名称"`.
|
|
54
|
+
- Do not search platform apps or reuse similar app names unless the user explicitly asks to reuse an existing app or gives an `appType`.
|
|
54
55
|
- Store platform-specific IDs only in `.openxiangda/state.json`.
|
|
55
56
|
- Use logical local codes for forms, pages, workflows, automations, and menus.
|
|
57
|
+
- Before scaffolding a new business app, read `../../references/best-practices.md` and pick an architecture from the initialized `examples/best-practices/` catalog. Do not generate a large single-file app page when a template pattern already covers the scenario.
|
|
56
58
|
- Use `openxiangda app snapshot <APP_XXX> --profile <name> --json` before changing an existing app.
|
|
57
59
|
|
|
58
60
|
## Resource State
|
|
@@ -62,3 +64,5 @@ Read `../../references/workspace-state.md` when changing `.openxiangda/state.jso
|
|
|
62
64
|
Read `../../references/openxiangda-api.md` when exact endpoint fields are needed.
|
|
63
65
|
|
|
64
66
|
Read `../../references/architecture-patterns.md` to understand the overall app structure (how forms, pages, menus, workflows, and permissions compose into an app, and the recommended `src/forms` / `src/pages` layout) before scaffolding or restructuring an app workspace.
|
|
67
|
+
|
|
68
|
+
Read `../../references/best-practices.md` before implementing app-level patterns such as status lifecycles, role governance, PC/mobile portals, high-performance data management pages, workflow boundaries, and automation.
|